/*
 * Copyright The OpenTelemetry Authors
 * SPDX-License-Identifier: Apache-2.0
 */

package com.xiashitech.agent.instrumentation.dubbo.common.inst;


import com.alibaba.dubbo.rpc.Result;
import com.xiashitech.agent.instrumentation.dubbo.common.inst.internal.DubboNetClientAttributesGetter;
import com.xiashitech.agent.instrumentation.dubbo.common.inst.internal.DubboNetServerAttributesGetter;
import io.opentelemetry.javaagent.shaded.instrumentation.api.instrumenter.AttributesExtractor;
import io.opentelemetry.javaagent.shaded.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.javaagent.shaded.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.javaagent.shaded.instrumentation.api.instrumenter.SpanNameExtractor;
import io.opentelemetry.javaagent.shaded.instrumentation.api.instrumenter.net.NetClientAttributesExtractor;
import io.opentelemetry.javaagent.shaded.instrumentation.api.instrumenter.net.NetServerAttributesExtractor;
import io.opentelemetry.javaagent.shaded.instrumentation.api.instrumenter.network.ClientAttributesExtractor;
import io.opentelemetry.javaagent.shaded.instrumentation.api.instrumenter.network.ServerAttributesExtractor;
import io.opentelemetry.javaagent.shaded.instrumentation.api.instrumenter.rpc.RpcClientAttributesExtractor;
import io.opentelemetry.javaagent.shaded.instrumentation.api.instrumenter.rpc.RpcServerAttributesExtractor;
import io.opentelemetry.javaagent.shaded.instrumentation.api.instrumenter.rpc.RpcSpanNameExtractor;
import io.opentelemetry.javaagent.shaded.io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.javaagent.shaded.io.opentelemetry.semconv.trace.attributes.SemanticAttributes;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;

public final class DubboTelemetryBuilder {

  private static final String INSTRUMENTATION_NAME = "com.xiashitech.dubbo-lt2.7";

  private final OpenTelemetry openTelemetry;
  @Nullable private String peerService;
  private final List<AttributesExtractor<DubboRequest, Result>> attributesExtractors =
      new ArrayList<>();

  DubboTelemetryBuilder(OpenTelemetry openTelemetry) {
    this.openTelemetry = openTelemetry;
  }

  public void setPeerService(String peerService) {
    this.peerService = peerService;
  }

  public DubboTelemetryBuilder addAttributesExtractor(
      AttributesExtractor<DubboRequest, Result> attributesExtractor) {
    attributesExtractors.add(attributesExtractor);
    return this;
  }

// TODO: TO DEL ON NEXT Version (OTEL 版本升级变更 1.29.0)

//  public DubboTelemetry build() {
//    DubboRpcAttributesGetter rpcAttributesGetter = DubboRpcAttributesGetter.INSTANCE;
//    SpanNameExtractor<DubboRequest> spanNameExtractor =
//        RpcSpanNameExtractor.create(rpcAttributesGetter);
//    DubboNetClientAttributesGetter netClientAttributesGetter = new DubboNetClientAttributesGetter();
//
//    InstrumenterBuilder<DubboRequest, Result> serverInstrumenterBuilder =
//        Instrumenter.<DubboRequest, Result>builder(
//                openTelemetry, INSTRUMENTATION_NAME, spanNameExtractor)
//            .addAttributesExtractors(RpcServerAttributesExtractor.create(rpcAttributesGetter))
//            .addAttributesExtractor(
//                NetServerAttributesExtractor.create(new DubboNetServerAttributesGetter()))
//            .addAttributesExtractors(attributesExtractors);
//
//    InstrumenterBuilder<DubboRequest, Result> clientInstrumenterBuilder =
//        Instrumenter.<DubboRequest, Result>builder(
//                openTelemetry, INSTRUMENTATION_NAME, spanNameExtractor)
//            .addAttributesExtractor(RpcClientAttributesExtractor.create(rpcAttributesGetter))
//            .addAttributesExtractor(NetClientAttributesExtractor.create(netClientAttributesGetter))
//            .addAttributesExtractors(attributesExtractors);
//
//    if (peerService != null) {
//      clientInstrumenterBuilder.addAttributesExtractor(
//          AttributesExtractor.constant(SemanticAttributes.PEER_SERVICE, peerService));
//    }
//
//    return new DubboTelemetry(
//        serverInstrumenterBuilder.buildServerInstrumenter(DubboHeadersGetter.INSTANCE),
//        clientInstrumenterBuilder.buildClientInstrumenter(DubboHeadersSetter.INSTANCE));
//  }

  public DubboTelemetry build() {
    DubboRpcAttributesGetter rpcAttributesGetter = DubboRpcAttributesGetter.INSTANCE;
    SpanNameExtractor<DubboRequest> spanNameExtractor =
            RpcSpanNameExtractor.create(rpcAttributesGetter);
    DubboNetClientAttributesGetter netClientAttributesGetter = new DubboNetClientAttributesGetter();

    InstrumenterBuilder<DubboRequest, Result> serverInstrumenterBuilder =
            Instrumenter.<DubboRequest, Result>builder(
                            openTelemetry, INSTRUMENTATION_NAME, spanNameExtractor)
                    .addAttributesExtractor(RpcServerAttributesExtractor.create(rpcAttributesGetter))
                    .addAttributesExtractor(ServerAttributesExtractor.create(new DubboNetServerAttributesGetter()))
                    .addAttributesExtractors(attributesExtractors);

    InstrumenterBuilder<DubboRequest, Result> clientInstrumenterBuilder =
            Instrumenter.<DubboRequest, Result>builder(openTelemetry, INSTRUMENTATION_NAME, spanNameExtractor)
                    .addAttributesExtractor(RpcClientAttributesExtractor.create(rpcAttributesGetter))
                    .addAttributesExtractor(ClientAttributesExtractor.create(netClientAttributesGetter))
                    .addAttributesExtractors(attributesExtractors);

    if (peerService != null) {
      clientInstrumenterBuilder.addAttributesExtractor(
              AttributesExtractor.constant(SemanticAttributes.PEER_SERVICE, peerService));
    }

    return new DubboTelemetry(
            serverInstrumenterBuilder.buildServerInstrumenter(DubboHeadersGetter.INSTANCE),
            clientInstrumenterBuilder.buildClientInstrumenter(DubboHeadersSetter.INSTANCE));
  }



}
